/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package byblos.negocio.reserva;

import byblos.negocio.Idioma;
import byblos.negocio.acomodacao.CategoriaAcomodacao;
import byblos.negocio.acomodacao.TipoAcomodacao;
import byblos.negocio.cliente.Cliente;
import byblos.negocio.pacote.Pacote;
import byblos.negocio.pacote.TipoPacote;
import byblos.negocio.reserva.prereserva.PreReserva;
import byblos.persistencia.Removivel;
import byblos.util.DataUtil;
import byblos.util.Moeda;
import byblos.util.Periodo;
import byblos.util.StringUtil;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Temporal;
import javax.persistence.Transient;

/**
 *
 * @author helena
 */
@Entity
@NamedQueries(value = {@NamedQuery(name = "ReservaPorArquivo", query = "SELECT r FROM Reserva r WHERE r.arquivada = ?1 AND r.removido = false"),
    @NamedQuery(name = "ReservaPorPeriodo", query = "SELECT r FROM Reserva r WHERE " +
    "?1 >= r.dataCheckin AND ?1 < r.dataCheckout OR " +
    "?2 > r.dataCheckin AND ?2 <= r.dataCheckout OR " +
    "?1 < r.dataCheckin AND ?2 > r.dataCheckout" +
    " AND r.removido = false"),
    @NamedQuery(name = "ReservaPorPeriodoPorArquivo", query = "SELECT r FROM Reserva r WHERE r.arquivada = ?3 AND (" +
    "?1 >= r.dataCheckin AND ?1 < r.dataCheckout OR " +
    "?2 > r.dataCheckin AND ?2 <= r.dataCheckout OR " +
    "?1 < r.dataCheckin AND ?2 > r.dataCheckout)" +
    " AND r.removido = false"),
    @NamedQuery(name = "ReservaPorPeriodoAcomodacaoOnline", query = "SELECT r FROM Reserva r WHERE " +
    "(?1 >= r.dataCheckin AND ?1 < r.dataCheckout OR " +
    "?2 > r.dataCheckin AND ?2 <= r.dataCheckout OR " +
    "?1 < r.dataCheckin AND ?2 > r.dataCheckout) AND " +
    "r.acomodacaoOnline = ?3" +
    " AND r.removido = false"),
    @NamedQuery(name = "ReservaPorTid", query = "SELECT r FROM Reserva r WHERE " +
    "r.tid = ?1")
})
public class Reserva implements Removivel, Serializable {

    @Id
    @GeneratedValue
    private int id;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Calendar dataReserva;
    private String nomeCliente;
    private String telefoneCliente;
    private String emailCliente;
    private String cpfCliente;
    private String rgCliente;
    private String passaporteCliente;
    private String enderecoCliente;
    private String comentarioCliente;
    private TipoAcomodacao tipoAcomodacao;
    private boolean arquivada;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Calendar dataCheckin;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Calendar dataCheckout;
    @ManyToOne
    private AcomodacaoOnline acomodacaoOnline;
    @ManyToOne
    private CategoriaAcomodacao categoriaAcomodacao;
    @ManyToOne
    private Pacote pacote;
    private TipoPacote tipoPacote;
    private boolean consulta;
    private double valor;
    private boolean pago;
    private boolean confirmado;
    @Transient
    private boolean disponivel;
    private boolean liberada;
    private boolean removido;
    private String tid;

    public String getTid() {
        return tid;
    }

    public void setTid(String tid) {
        this.tid = tid;
    }

    public Reserva() {
        dataReserva = Calendar.getInstance();
    }

    public Reserva(AcomodacaoOnline acomodacaoOnline, PreReserva preReserva) {
        this();
        System.out.println("Reserva(AcomodacaoOnline, PreReserva)");
        dataCheckin = preReserva.getCheckin();
        System.out.println("preReserva.getCheckout() " + DataUtil.toString(preReserva.getCheckout()));
        dataCheckout = preReserva.getCheckout();
        tipoAcomodacao = preReserva.getTipoAcomodacao();
        pacote = preReserva.getPacote();
        if (pacote != null) {
            tipoPacote = pacote.getTipoPacote();
        }
        this.acomodacaoOnline = acomodacaoOnline;
        categoriaAcomodacao = acomodacaoOnline.getCategoria();
    }

    public String getStringStatus() {
        if (isConsulta()) {
            return "";
        } else {
            if (isPago()) {
                return "Pago";
            } else {
                return "Não Pago";
            }
        }
    }

    public Cliente getCliente(Idioma idioma) {
        Cliente cliente = new Cliente();
        cliente.setEmail(emailCliente);
        cliente.setNome(nomeCliente);
        cliente.setTelefone(telefoneCliente);
        cliente.setIdioma(idioma);
        return cliente;
    }

    public boolean isLiberada() {
        return liberada;
    }

    public void setLiberada(boolean liberada) {
        this.liberada = liberada;
    }

    public void liberar() {
        liberada = true;
    }

    public void arquivar() {
        liberar();
        setArquivada(true);
    }

    public Periodo getPeriodo() {
        return new Periodo(dataCheckin, dataCheckout);
    }

    public boolean temIndisponibilidade() {
        return acomodacaoOnline.temIndisponibilidade(this);
    }

    public void verificarSeEhConsulta(List<Pacote> pacotesConflitantes) {
        boolean isConsulta = !disponivel || tipoAcomodacao.getCapacidade() > acomodacaoOnline.getCategoria().getCapacidade().getCapacidade() || getNumeroNoites() < 2;
        if (!isConsulta && podeSerBloqueada()) {
            for (Pacote pacoteConflitante : pacotesConflitantes) {
                if (!pacoteConflitante.equals(pacote) &&
                        pacoteConflitante.isExclusividadeReserva()) {
                    isConsulta = true;
                    break;
                }
            }
        }
        setConsulta(isConsulta);
    }

    private boolean podeSerBloqueada() {
        return !temPacote() || !getPacote().isExclusividadeReserva() || !getPacote().getPeriodo().isPeriodoContidoAqui(getPeriodo());
    }

    public void calcularTotal(int quantidadeDiasTemporada) {
        valor = getValor(quantidadeDiasTemporada);
    }

    private double getValor(int quantidadeDiasTemporada) {
        if (pacote == null) {
            int totalDiasReserva = getNumeroNoites();
            int quantidadeDiasNormais = totalDiasReserva - quantidadeDiasTemporada;
            double total = 0;
            total += categoriaAcomodacao.getValor(tipoAcomodacao, false) * quantidadeDiasNormais;
            total += categoriaAcomodacao.getValor(tipoAcomodacao, true) * quantidadeDiasTemporada;
            return total;
        } else {
            return pacote.getValor(categoriaAcomodacao, tipoAcomodacao, quantidadeDiasTemporada > 0);
        }
    }

    public String getStringTipoReserva() {
        if (isConsulta()) {
            return "Consulta";
        } else {
            return "Reserva";
        }
    }

    public boolean isPago() {
        return pago;
    }

    public boolean temPacote() {
        return pacote != null;
    }

    public void setPago(boolean pago) {
        this.pago = pago;
    }

    public boolean isConfirmado() {
        return confirmado;
    }

    public void setConfirmado(boolean confirmado) {
        this.confirmado = confirmado;
    }

    public boolean isConsulta() {
        return consulta;
    }

    public void setConsulta(boolean consulta) {
        this.consulta = consulta;
    }

    public int getNumeroNoites() {
        return DataUtil.getDiferencaEmDias(dataCheckout, dataCheckin);
    }

    public boolean isDisponivel() {
        return disponivel;
    }

    public void setDisponivel(boolean disponivel) {
        this.disponivel = disponivel;
    }

    public boolean isArquivada() {
        return arquivada;
    }

    public void setArquivada(boolean arquivada) {
        this.arquivada = arquivada;
    }

    public CategoriaAcomodacao getCategoriaAcomodacao() {
        return categoriaAcomodacao;
    }

    public void setCategoriaAcomodacao(CategoriaAcomodacao categoriaAcomodacao) {
        this.categoriaAcomodacao = categoriaAcomodacao;
    }

    public Calendar getDataCheckin() {
        return dataCheckin;
    }

    public String getStringDataCheckin() {
        return DataUtil.toString(dataCheckin);
    }

    public void setDataCheckin(Calendar dataCheckin) {
        this.dataCheckin = dataCheckin;
    }

    public String getStringDataCheckout() {
        return DataUtil.toString(dataCheckout);
    }

    public Calendar getDataCheckout() {
        return dataCheckout;
    }

    public void setDataCheckout(Calendar dataCheckout) {
        this.dataCheckout = dataCheckout;
    }

    public Calendar getDataReserva() {
        return dataReserva;
    }

    public String getStringDataReserva() {
        return DataUtil.toString(dataReserva);
    }

    public void setDataReserva(Calendar dataReserva) {
        this.dataReserva = dataReserva;
    }

    public AcomodacaoOnline getAcomodacaoOnline() {
        return acomodacaoOnline;
    }

    public void setAcomodacaoOnline(AcomodacaoOnline acomodacaoOnline) {
        this.acomodacaoOnline = acomodacaoOnline;
    }

    public String getNomeCliente() {
        return nomeCliente;
    }

    public void setNomeCliente(String nomeCliente) {
        this.nomeCliente = nomeCliente;
    }

    public String getComentarioCliente() {
        return comentarioCliente;
    }

    public void setComentarioCliente(String comentarioCliente) {
        this.comentarioCliente = comentarioCliente;
    }

    public String getEmailCliente() {
        return emailCliente;
    }

    public void setEmailCliente(String emailCliente) {
        this.emailCliente = emailCliente;
    }

    public String getTelefoneCliente() {
        return telefoneCliente;
    }

    public void setTelefoneCliente(String telefoneCliente) {
        this.telefoneCliente = telefoneCliente;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Pacote getPacote() {
        return pacote;
    }

    public void setPacote(Pacote pacote) {
        this.pacote = pacote;
    }

    public TipoAcomodacao getTipoAcomodacao() {
        return tipoAcomodacao;
    }

    public void setTipoAcomodacao(TipoAcomodacao tipoAcomodacao) {
        this.tipoAcomodacao = tipoAcomodacao;
    }

    public TipoPacote getTipoPacote() {
        return tipoPacote;
    }

    public void setTipoPacote(TipoPacote tipoPacote) {
        this.tipoPacote = tipoPacote;
    }

    public double getValor() {
        return valor;
    }

    public String getValorComVirgula() {
        return getValorMoeda().toString();
    }

    public Moeda getValorMoeda() {
        return new Moeda(valor);
    }

    public String getValorVisa() {
        String valorVisa = new DecimalFormat("0.00").format(valor);
        valorVisa = valorVisa.replace(",", "");
        valorVisa = valorVisa.replace(".", "");
        return valorVisa;
    }

    public void setValor(double valor) {
        this.valor = valor;
    }

    public String getCpfCliente() {
        return cpfCliente;
    }

    public void setCpfCliente(String cpfCliente) {
        this.cpfCliente = cpfCliente;
    }

    public String getEnderecoCliente() {
        return enderecoCliente;
    }

    public void setEnderecoCliente(String enderecoCliente) {
        this.enderecoCliente = enderecoCliente;
    }

    public String getPassaporteCliente() {
        return passaporteCliente;
    }

    public void setPassaporteCliente(String passaporteCliente) {
        this.passaporteCliente = passaporteCliente;
    }

    public String getRgCliente() {
        return rgCliente;
    }

    public void setRgCliente(String rgCliente) {
        this.rgCliente = rgCliente;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Reserva other = (Reserva) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + this.id;
        return hash;
    }

    @Override
    public String toString() {
        return DataUtil.toString(dataReserva);
    }

    public void setRemovido(boolean removido) {
        this.removido = removido;
    }

    public boolean isRemovido() {
        return removido;
    }
}
